package com.abso.mp3tunes.locker.ui.actions;

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.lang.reflect.InvocationTargetException;
import java.util.List;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Shell;

import com.abso.mp3tunes.locker.core.data.Track;
import com.abso.mp3tunes.locker.ui.LockerPlugin;
import com.abso.mp3tunes.locker.ui.viewers.LockerViewer;

/**
 * An abstract base class for actions able to export playlists in popular
 * formats such as M3U.
 */
public abstract class AbstractExportPlaylistAction extends
		AbstractLockerViewerAction {

	/** The selected elements. */
	private List elements;

	/**
	 * Constructs a new action.
	 * 
	 * @param label
	 *            the action's text.
	 * @param imageDescriptor
	 *            the action's image.
	 * @param lockerViewer
	 *            the Locker tree viewer this action is based on.
	 */
	public AbstractExportPlaylistAction(String label,
			ImageDescriptor imageDescriptor, LockerViewer lockerViewer) {
		super(label, imageDescriptor, lockerViewer);
	}

	/**
	 * Sets the current selection.
	 * 
	 * @param elements
	 *            the selected elements.
	 */
	public void setSelectedElements(List elements) {
		this.elements = elements;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see org.eclipse.jface.action.Action#run()
	 */
	public void run() {
		FileDialog fileDialog = new FileDialog(LockerPlugin
				.getActiveWorkbenchShell());
		fileDialog.setFilterExtensions(getFileFilterExtensions());
		final String filePath = fileDialog.open();
		if (filePath == null) {
			return;
		}
		IRunnableWithProgress runnable = new IRunnableWithProgress() {
			public void run(IProgressMonitor monitor)
					throws InvocationTargetException, InterruptedException {
				Track[] tracksToAdd = unwrapTracks(elements, monitor);
				if (tracksToAdd == null) {
					return;
				}
				PrintWriter writer = null;
				try {
					monitor.beginTask("Adding tracks", tracksToAdd.length);
					String playlistPath = getPlaylistPath(filePath);
					writer = new PrintWriter(new OutputStreamWriter(
							new FileOutputStream(playlistPath),
							getFileEncoding()));
					exportTracks(tracksToAdd, writer, monitor);
				} catch (IOException e) {
					showErrorDialog("Error", "Unable to create the playlist",
							"Error creating the playlist", e);
				} finally {
					monitor.done();
					if (writer != null) {
						writer.flush();
						writer.close();
					}
				}
			}
		};
		try {
			ProgressMonitorDialog dialog = new ProgressMonitorDialog(
					LockerPlugin.getActiveWorkbenchShell()) {
				protected void configureShell(final Shell shell) {
					super.configureShell(shell);
					shell.setText("Playlist Creation");
				}
			};
			dialog.run(true, true, runnable);
		} catch (InvocationTargetException e) {
		} catch (InterruptedException e) {
		}
	}

	/**
	 * Returns a valid playlist path given the file path selected in the file dialog.
	 * This method usually appends a specific extension to file path, if it does not
	 * have it.
	 * 
	 * @param filePath   the file path obtained from the file dialog.
	 * @return   a valid playlist path.
	 */
	protected abstract String getPlaylistPath(String filePath);

	/**
	 * Returns the valid file filter extensions for this specific playlist.
	 * 
	 * @return the file filter extensions (such as <code>*.m3u</code>).
	 */
	protected abstract String[] getFileFilterExtensions();

	/**
	 * Gets the character set encoding of the exported file.
	 * 
	 * @return the character set encoding (such as <code>UTF-8</code>).
	 */
	protected abstract String getFileEncoding();

	/**
	 * Exports the tracks into the playlist.
	 * 
	 * @param tracks
	 *            the set of tracks being exported.
	 * @param writer
	 *            the output writer (it is no required to close it).
	 * @param monitor
	 *            the progress monitor, to be advanced using
	 *            <i>monitor.worked(1)</i> each time a track is processed.
	 * @throws IOException
	 *             if an error occurred exporting the tracks.
	 */
	protected abstract void exportTracks(Track[] tracks,
			PrintWriter writer, IProgressMonitor monitor) throws IOException;

}
